/*
 * Copyright (c) 2007 The Trustees of Indiana University. All rights reserved.
 * IU CSCI B534 Distributed Systems 2007-02-01 http://www.cs.indiana.edu/classes/b534
 */

package edu.indiana.cs.b534.torrent.struct;

import edu.indiana.cs.b534.torrent.TString;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;

public class TStringImpl implements TString {


    protected String value;
    private static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("debug"));

    public static TString deserialize(InputStream inStream) throws IOException {
        char ch = 0;
        StringBuffer strBuffer = new StringBuffer(); // dont expect length to be > 20 bytes
        // read the length prefix
        ch = (char)inStream.read();
        if (DEBUG) System.out.println("S> " + ((char)ch));
        while(ch != ':') {
            strBuffer.append(ch);
            ch = (char)inStream.read();
            if (DEBUG) System.out.println("S> " + ((char)ch));
        }
        if (DEBUG) System.out.println("S> bytes = " + strBuffer.toString());
        int length = Integer.parseInt(strBuffer.toString());
        // read the chars of the string

        ByteBuffer byteBuffer = ByteBuffer.allocate(length);
        byte by;
        for(int i=0; i<length; i++){
            by = (byte)inStream.read();
            if (DEBUG) System.out.println("S> " + ((char)by));
            byteBuffer.put(by);
        }
        byteBuffer.rewind();
        // create and return an instance
        TStringImpl instance = new TStringImpl();
        CharBuffer charBuffer = CHARSET.decode(byteBuffer);
        instance.value = new String(charBuffer.array(), 0, charBuffer.limit());
        if (DEBUG) System.out.println("SVALUE=" + instance.value);
        return instance;
    }

    public static TString newInstance() {
        return new TStringImpl();
    }
    
    public static TString newInstance(String value) {
        TString tstr = new TStringImpl();
        tstr.setValue(value);
        return tstr;
    }

    public String getValue(){
        return value;
    }

    public void setValue(String value_){
    	if(value_ == null){
    		throw new RuntimeException();
    	}
        value = value_;
    }

    public OutputStream serialize(OutputStream out) throws IOException {
        ByteBuffer valBuffer = CHARSET.encode(getValue());
        ByteBuffer lenBuffer = CHARSET.encode(String.valueOf(valBuffer.limit()));
        //ByteBuffer colBuffer = CHARSET.encode(":");

        out.write(lenBuffer.array(), 0, lenBuffer.limit()); // length
        out.write(':'); // colon
        out.write(valBuffer.array(), 0, valBuffer.limit()); // value
        return out;
    }

    public int hashCode() { return new String(getValue()).hashCode(); }
    public boolean equals(Object other){
        if(other == null) return false;
        if(!TString.class.isAssignableFrom(other.getClass())) return false;
        String otherVal = ((TString)other).getValue();
        if(value == otherVal) return true;
        if(value == null || otherVal == null) return false;
        return value.equals(otherVal);
    }
    public String toString() { return getValue(); }
}
